﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using BCGPSCommon;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace BCGPSCommon
{
    public class RedisService : IRedisService
    {
        private static readonly ConnectionMultiplexer connection;
        private readonly ISubscriber subscriber;
        private readonly IDatabase redisDatabase;
        //private TimeSpan expiry = TimeSpan.FromMinutes(30);
        private static string redisConnectionString { get; set; }
        public bool ServerExists { get; set; }
        static RedisService()
        {
            if (connection == null)
            {
                redisConnectionString = GeneralContainer.configuration["Redis:RedisConnectionString"];
                var config = new ConfigurationOptions
                {
                    AbortOnConnectFail = false,
                    AllowAdmin = true,
                    ConnectTimeout = 15000,
                    SyncTimeout = 15000,
                    AsyncTimeout = 15000,
                    Password = redisConnectionString.Split(',')[1].Replace("password=", ""),
                    EndPoints = { redisConnectionString.Split(',')[0] }
                };
                connection = ConnectionMultiplexer.Connect(config);
            }
        }

        public RedisService()
        {
            if (connection == null)
            {
                this.ServerExists = false;
            }
            else
            {
                int databaseNo = 0;
                string redisDatabaseNoStr = GeneralContainer.configuration["Redis:RedisDatabaseNo"];
                string ipstr = BCGPSCommon.IPHelper.GetHostName();
                if (ipstr== "DESKTOP-V829TES")
                    redisDatabaseNoStr = GeneralContainer.configuration["Redis:RedisDatabaseNo-DEBUG"];

                if (!string.IsNullOrWhiteSpace(redisDatabaseNoStr))
                {
                    databaseNo = Convert.ToInt32(redisDatabaseNoStr);
                }
                this.redisDatabase = connection.GetDatabase(databaseNo);
                this.subscriber = connection.GetSubscriber();
                this.ServerExists = true;
            }
        }

        public Task AddHashAsync<T>(string key, string hashKey, T obj)
        {
            string objString = JsonConvert.SerializeObject(obj, GeneralContainer.JsonSerializerSettings);

            var v = new KeyValuePair<RedisValue, RedisValue>(hashKey, objString); 
            return redisDatabase.HashSetAsync(key, hashKey, objString);
        }
         
        public T GetHashObj<T>(string key,string hashKey)
        {
            string str = redisDatabase.HashGetAsync(key, hashKey).GetAwaiter().GetResult();
            if (string.IsNullOrEmpty(str))
                return default(T);
            return JsonConvert.DeserializeObject<T>(str, GeneralContainer.JsonSerializerSettings);
        }

       public Task<bool> DeleteHashObjAsync(string key,string hashKey)
        {
            return   redisDatabase.HashDeleteAsync(key, hashKey);
        }

        public Task<bool> DeleteAsync(string key)
        {
            return redisDatabase.KeyDeleteAsync(key);
        }

        public Task<bool> AddAsync<T>(string key, T obj)
        {
            string objString = JsonConvert.SerializeObject(obj, GeneralContainer.JsonSerializerSettings);

            return  this.redisDatabase.StringSetAsync(key, objString);
        }
        public bool Exists(string key)
        {
            ThreadPool.SetMinThreads(200, 200);
            return this.redisDatabase.KeyExistsAsync(key).GetAwaiter().GetResult();
        }

        public Task <HashEntry[]> GetHashAllAsync(string key)
        {
            return  this.redisDatabase.HashGetAllAsync(key);
        }


        public T Get<T>(string key)
            where T : class
        { 
            string redisString = this.redisDatabase.StringGetAsync(key).GetAwaiter().GetResult();

            if (redisString == null)
            {
                return null;
            }

            return JsonConvert.DeserializeObject<T>(redisString, GeneralContainer.JsonSerializerSettings);
        }

        public Task<RedisValue[]> GetGroupList(string key)
        {
            return this.redisDatabase.ListRangeAsync(key);
        }

        #region 获取缓存服务器配置信息
        private string GetRedisHostingInfo(out int port)
        {
            string host = redisConnectionString.Split(',')[0];
            if (string.IsNullOrWhiteSpace(host))
            {
                throw new ArgumentException("Redis缓存配置文件缺少必要的服务器地址信息。");
            }
            if (host.IndexOf(":") == -1)
            {
                throw new ArgumentException("Redis缓存服务器地址信息缺少端口配置信息。");
            }
            string[] hostPoint = host.Split(":");
            if (string.IsNullOrWhiteSpace(hostPoint[1]))
            {
                throw new ArgumentException("Redis缓存服务器地址信息中端口配置信息不能为空。");
            }
            if (!int.TryParse(hostPoint[1], out port))
            {
                throw new ArgumentException("Redis缓存服务器地址信息中端口配置信息不是正确的端口号。");
            }
            return hostPoint[0];
        }
        #endregion

        #region 清理缓存数据库
        public void FlushAsync(int databasesNo)
        {
            string host = GetRedisHostingInfo(out int port);

            FlushDatabaseAsync(host, port, databasesNo);
 
        }

        private void FlushDatabaseAsync(string host, int port, int databaseNo)
        {
            connection.GetServer(host, port).FlushDatabaseAsync(databaseNo);
        }
        #endregion


        public bool Add<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
        {

            string objString = JsonConvert.SerializeObject(obj, GeneralContainer.JsonSerializerSettings);

            return this.redisDatabase.StringSetAsync(key, objString, expiry).GetAwaiter().GetResult();
        }

    }
}
